//********************************************************************************************************
// Product Name: MapWindow.dll Alpha
// Description:  The basic module for MapWindow version 6.0
//********************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either expressed or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
//
// The Original Code is from MapWindow.dll version 6.0
//
// The Initial Developer of this Original Code is Ted Dunsford. Created 2/26/2010 5:06:40 PM
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
//
//********************************************************************************************************

using System;
using System.Data;
using MapWindow.Data;
using MapWindow.Geometries;
using MapWindow.Projections;
using Point = MapWindow.Geometries.Point;

namespace StandaloneTest
{


    /// <summary>
    /// ExampleCode
    /// </summary>
    public class ExampleCode
    {
        #region Private Variables

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new instance of ExampleCode
        /// </summary>
        public ExampleCode()
        {

        }

        #endregion

        private void BuildPoints()
        {
            // Setup a new "shapefile" by using the featureset object
            FeatureSet fs = new FeatureSet(FeatureTypes.Point);
            // You can control things like the projection with this object
            fs.Projection = KnownCoordinateSystems.Projected.UtmNad1983.NAD1983UTMZone11N;
            // The DataTable is a standard .Net DataTable, so you can add columns the normal way and use with DataGrid controls
            fs.DataTable.Columns.Add("Elevation", typeof(int));

            // Set up the specs for creating random points.  If you already know the point values from a file this is not necessary.
            Random rnd = new Random(DateTime.Now.Millisecond);
            const int YMIN = 0;
            const int YSPAN = 1000;
            const int XMIN = 0;
            const int XSPAN = 1000;

            // In a loop we are creating 100 different points using the box established above.
            for (int i = 0; i < 100; i++)
            {
                // A coordinate is the simple X and Y location
                Coordinate c = new Coordinate(XMIN + rnd.NextDouble() * XSPAN, YMIN + rnd.NextDouble() * YSPAN);
                // A point has geoemtry capabilities like testing intersection with polygons etc.
                Point pt = new Point(c);
                // A feature also has attributes related to the featureset
                // Features can be created directly, passing the point into the constructor, but there is a glitch
                // right now that may not update the DataRow property of the feature correctly once it is added.
                IFeature currentFeature = fs.AddFeature(pt);

                // Working with the current feature allows you to control attribute content as well as the feature content.
                currentFeature.DataRow["Elevation"] = rnd.Next(0, 100);
            }
            fs.SaveAs(@"C:\test.shp", true);
        }


        private void BuildLines()
        {
            // Setup a new "shapefile" by using the featureset object
            FeatureSet fs = new FeatureSet(FeatureTypes.Line);
            // You can control things like the projection with this object
            fs.Projection = KnownCoordinateSystems.Projected.UtmNad1983.NAD1983UTMZone11N;
            // The DataTable is a standard .Net DataTable, so you can add columns the normal way and use with DataGrid controls
            fs.DataTable.Columns.Add("Elevation", typeof(int));

            // Set up the specs for creating random points.  If you already know the point values from a file this is not necessary.
            Random rnd = new Random(DateTime.Now.Millisecond);
            const int YMIN = 0;
            const int YSPAN = 1000;
            const int XMIN = 0;
            const int XSPAN = 1000;

            // In a loop we are creating 100 different points using the box established above.
            for (int i = 0; i < 10; i++)
            {
                // An array of coordinates that defines a single, continuous line
                Coordinate[] coords = new Coordinate[10];
                for (int j = 0; j < 10; j++)
                {
                    // A coordinate is the simple X and Y location
                    coords[j] = new Coordinate(XMIN + rnd.NextDouble() * XSPAN, YMIN + rnd.NextDouble() * YSPAN);
                }

                Coordinate c = new Coordinate(XMIN + rnd.NextDouble() * XSPAN, YMIN + rnd.NextDouble() * YSPAN);
                // A point has geoemtry capabilities like testing intersection with polygons etc.
                LineString ls = new LineString(coords);
                // A feature also has attributes related to the featureset
                // Features can be created directly, passing the point into the constructor, but there is a glitch
                // right now that may not update the DataRow property of the feature correctly once it is added.
                IFeature currentFeature = fs.AddFeature(ls);

                // Working with the current feature allows you to control attribute content as well as the feature content.
                currentFeature.DataRow["Elevation"] = rnd.Next(0, 100);
            }
            fs.SaveAs(@"C:\test.shp", true);
        }

        /// <summary>
        /// MultiLineString represents several, disconnected lines.  MultiPoint
        /// and MultiPolygon work the same way, so this example covers all of these.
        /// For MultiPoint, make sure the feature specification is multi-point or else
        /// the shapefile may not save correctly.  The other multi-formats are supported
        /// as multi-part lines/polygons in the shapefile.
        /// </summary>
        private void BuildMultiLineString()
        {
            // Setup a new "shapefile" by using the featureset object
            FeatureSet fs = new FeatureSet(FeatureTypes.Line);
            // You can control things like the projection with this object
            fs.Projection = KnownCoordinateSystems.Projected.UtmNad1983.NAD1983UTMZone11N;
            // The DataTable is a standard .Net DataTable, so you can add columns the normal way and use with DataGrid controls
            fs.DataTable.Columns.Add("Elevation", typeof(int));

            // Set up the specs for creating random points.  If you already know the point values from a file this is not necessary.
            Random rnd = new Random(DateTime.Now.Millisecond);
            const int YMIN = 0;
            const int YSPAN = 1000;
            const int XMIN = 0;
            const int XSPAN = 1000;

            LineString[] strings = new LineString[10];

            // In a loop we are creating 100 different points using the box established above.
            for (int i = 0; i < 10; i++)
            {
                // An array of coordinates that defines a single, continuous line
                Coordinate[] coords = new Coordinate[10];
                for (int j = 0; j < 10; j++)
                {
                    // A coordinate is the simple X and Y location
                    coords[j] = new Coordinate(XMIN + rnd.NextDouble() * XSPAN, YMIN + rnd.NextDouble() * YSPAN);
                }

                Coordinate c = new Coordinate(XMIN + rnd.NextDouble() * XSPAN, YMIN + rnd.NextDouble() * YSPAN);
                // A point has geoemtry capabilities like testing intersection with polygons etc.
                LineString ls = new LineString(coords);

                // collect all the LineStrings we create in a single array.
                strings[i] = ls;

            }

            MultiLineString mls = new MultiLineString(strings);

            // A feature also has attributes related to the featureset
            IFeature currentFeature = fs.AddFeature(mls);

            // Working with the current feature allows you to control attribute content as well as the feature content.
            currentFeature.DataRow["Elevation"] = rnd.Next(0, 100);

            fs.SaveAs(@"C:\test.shp", true);
        }



        private void BuildPolygon()
        {
            // Setup a new "shapefile" by using the featureset object
            FeatureSet fs = new FeatureSet(FeatureTypes.Line);
            // You can control things like the projection with this object
            fs.Projection = KnownCoordinateSystems.Projected.UtmNad1983.NAD1983UTMZone11N;
            // The DataTable is a standard .Net DataTable, so you can add columns the normal way and use with DataGrid controls
            fs.DataTable.Columns.Add("Elevation", typeof(int));

            // Set up the specs for creating random points.  If you already know the point values from a file this is not necessary.
            Random rnd = new Random(DateTime.Now.Millisecond);
            const int YMIN = 0;
            const int YSPAN = 1000;
            const int XMIN = 0;
            const int XSPAN = 1000;

            // In a loop we are creating 100 different points using the box established above.
            for (int i = 0; i < 10; i++)
            {
                // random center
                Coordinate center = new Coordinate(XMIN + rnd.NextDouble() * XSPAN, YMIN + rnd.NextDouble() * YSPAN);
                // random radius from 10 to 100
                double radius = 10 + rnd.Next() * 90;
                // An array of coordinates that defines a single, continuous line
                Coordinate[] coords = new Coordinate[36];
                // Filled regions are defined by ArcGIS as clockwise
                for (int j = 35; j >= 0; j--)
                {
                    // A coordinate is the simple X and Y location
                    coords[j] = new Coordinate(center.X + radius * Math.Cos(j * Math.PI / 36), center.Y + radius * Math.Sin(j * Math.PI / 36));
                }


                // A point has geoemtry capabilities like testing intersection with polygons etc.
                Polygon pg = new Polygon(coords);
                // A feature also has attributes related to the featureset
                // Features can be created directly, passing the point into the constructor, but there is a glitch
                // right now that may not update the DataRow property of the feature correctly once it is added.
                IFeature currentFeature = fs.AddFeature(pg);

                // Working with the current feature allows you to control attribute content as well as the feature content.
                currentFeature.DataRow["Elevation"] = rnd.Next(0, 100);
            }
            fs.SaveAs(@"C:\test.shp", true);
        }



        private void BuildPolygonWithHole()
        {
            // Setup a new "shapefile" by using the featureset object
            FeatureSet fs = new FeatureSet(FeatureTypes.Line);
            // You can control things like the projection with this object
            fs.Projection = KnownCoordinateSystems.Projected.UtmNad1983.NAD1983UTMZone11N;
            // The DataTable is a standard .Net DataTable, so you can add columns the normal way and use with DataGrid controls
            fs.DataTable.Columns.Add("Elevation", typeof(int));



            // Set up the specs for creating random points.  If you already know the point values from a file this is not necessary.
            Random rnd = new Random(DateTime.Now.Millisecond);
            const int YMIN = 0;
            const int YSPAN = 1000;
            const int XMIN = 0;
            const int XSPAN = 1000;

            // In a loop we are creating 100 different points using the box established above.
            for (int i = 0; i < 10; i++)
            {
                // random center
                Coordinate center = new Coordinate(XMIN + rnd.NextDouble() * XSPAN, YMIN + rnd.NextDouble() * YSPAN);
                // random radius from 10 to 100
                double radius = 10 + rnd.Next() * 90;
                // An array of coordinates that defines a single, continuous line
                Coordinate[] coords = new Coordinate[36];
                // Filled regions are defined by Shapefile specs to be clockwise
                for (int j = 35; j >= 0; j--)
                {
                    // A coordinate is the simple X and Y location
                    coords[j] = new Coordinate(center.X + radius * Math.Cos(j * Math.PI / 36), center.Y + radius * Math.Sin(j * Math.PI / 36));
                }

                Coordinate[] hole = new Coordinate[36];
                // Holes are defined as counter clockwise by shapefile spec.
                // In fact rendering rules are as long as it is in the opposite direction
                // and overlaps the shell it will be drawn as a hole. 
                for (int j = 0; j < 36; j++)
                {
                    // A coordinate is the simple X and Y location
                    hole[j] = new Coordinate(center.X + radius / 2 * Math.Cos(j * Math.PI / 36), center.Y + radius / 2 * Math.Sin(j * Math.PI / 36));
                }
                // Create a LinearRing for the hole
                LinearRing ring = new LinearRing(hole);
                // Since multiple holes are supported, make this an array with one member.
                LinearRing[] rings = new LinearRing[1];
                rings[0] = ring;

                // Temporarilly there is no constructor overload that just takes an array
                // of coordinates but also has rings, so this creates the linear ring that 
                // represents the shell.
                LinearRing shell = new LinearRing(coords);

                // A point has geoemtry capabilities like testing intersection with polygons etc.
                Polygon pg = new Polygon(shell, rings);

                // A feature also has attributes related to the featureset
                // Features can be created directly, passing the point into the constructor, but there is a glitch
                // right now that may not update the DataRow property of the feature correctly once it is added.
                IFeature currentFeature = fs.AddFeature(pg);

                // Working with the current feature allows you to control attribute content as well as the feature content.
                currentFeature.DataRow["Elevation"] = rnd.Next(0, 100);
            }
            fs.SaveAs(@"C:\test.shp", true);
        }

        private void CreatePointsFromTable(DataTable source)
        {
            // Setup a new "shapefile" by using the featureset object
            FeatureSet fs = new FeatureSet(FeatureTypes.Point);

            // Ensure that the columns are set up the same way as your data table
            fs.CopyTableSchema(source);

            foreach (DataRow row in source.Rows)
            {
                double x = (double)row["Longitude"];
                double y = (double)row["Latitude"];
                Point pt = new Point(x, y);
                IFeature f = fs.AddFeature(pt);
                f.DataRow.ItemArray = row.ItemArray;
            }
            // At this point, fs.DataTable will have all the values,
            // and all the features in the featureset will be defined.

        }

    }
}
